﻿using Autofac;
using Autofac.Core;
using Autofac.Extensions.DependencyInjection;
using Dotnet.Utils;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Module = Autofac.Module;

namespace Dotnet.Utils.Utility.Dependency.Autofac
{
    public class Init
    {
        public void init(IServiceCollection services)
        {
            AutofacContainer.Build(services);
            var serviceProvider = AutofacContainer.Resolve<IServiceProvider>();

            //builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureContainer<ContainerBuilder>(_builder => _builder.RegisterModule(new AutofacModuleRegister()));
            //...
            // IocManager.Instance.Container = app.Services.GetAutofacRoot();

            //获取服务
            var testIoc = IocManager.Instance.GetService<string>();

            //通过特性标签注入实体类可以使用Autofac.Annotation：https://github.com/yuzd/Autofac.Annotation
        }
    }

    public class AutofacModuleRegister : Module
    {
        private static string[] _otherAssembly;
        private static List<Type> _types = new List<Type>();
        private static Dictionary<Type, Type> _dicTypes = new Dictionary<Type, Type>();

        //重写Autofac管道Load方法，在这里注册注入
        protected override void Load(ContainerBuilder builder)
        {
            //程序集注入业务服务
            var IAppServices = Assembly.Load("Application");
            var AppServices = Assembly.Load("Application");
            //根据名称约定（服务层的接口和实现均以Service结尾），实现服务接口和服务实现的依赖
            builder.RegisterAssemblyTypes(IAppServices, AppServices)
              .Where(t => t.Name.EndsWith("Service"))
              .AsImplementedInterfaces();

            var assemblysServices = Assembly.Load("Service");
            var assemblysRepository = Assembly.Load("Repository");
            builder.RegisterAssemblyTypes(assemblysServices).Where(t => t.Name.EndsWith("Service")).AsSelf().AsImplementedInterfaces();
            builder.RegisterAssemblyTypes(assemblysRepository).Where(t => t.Name.EndsWith("Repository")).AsSelf().AsImplementedInterfaces();

            builder.RegisterType<ServiceProvider>().As<IServiceProvider>().InstancePerDependency();

            //注册一个实体
            builder.RegisterInstance(typeof(ServiceProvider)).InstancePerDependency();

            if (_otherAssembly != null)
            {
                foreach (var item in _otherAssembly)
                {
                    builder.RegisterAssemblyTypes(Assembly.Load(item));
                }
            }

            if (_types != null)
            {
                foreach (var type in _types)
                {
                    builder.RegisterType(type);
                }
            }

            if (_dicTypes != null)
            {
                foreach (var dicType in _dicTypes)
                {
                    builder.RegisterType(dicType.Value).As(dicType.Key);
                }
            }
        }

        /// <summary>
        /// 注册程序集
        /// </summary>
        /// <param name="assemblies">程序集名称的集合</param>
        public static void Register(params string[] assemblies)
        {
            _otherAssembly = assemblies;
        }

        /// <summary>
        /// 注册类型
        /// </summary>
        /// <param name="types"></param>
        public static void Register(params Type[] types)
        {
            _types.AddRange(types.ToList());
        }

        /// <summary>
        /// 注册程序集。
        /// </summary>
        /// <param name="implementationAssemblyName"></param>
        /// <param name="interfaceAssemblyName"></param>
        public static void Register(string implementationAssemblyName, string interfaceAssemblyName)
        {
            var implementationAssembly = Assembly.Load(implementationAssemblyName);
            var interfaceAssembly = Assembly.Load(interfaceAssemblyName);
            var implementationTypes =
                implementationAssembly.DefinedTypes.Where(t =>
                    t.IsClass && !t.IsAbstract && !t.IsGenericType && !t.IsNested);
            foreach (var type in implementationTypes)
            {
                var interfaceTypeName = interfaceAssemblyName + ".I" + type.Name;
                var interfaceType = interfaceAssembly.GetType(interfaceTypeName);
                if (interfaceType.IsAssignableFrom(type))
                {
                    _dicTypes.Add(interfaceType, type);
                }
            }
        }

        /// <summary>
        /// 注册
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TImplementation"></typeparam>
        public static void Register<TInterface, TImplementation>() where TImplementation : TInterface
        {
            _dicTypes.Add(typeof(TInterface), typeof(TImplementation));
        }
    }

    /// <summary>
    /// Autofac IOC 容器
    /// </summary>
    public class AutofacContainer
    {
        private static ContainerBuilder _builder = new ContainerBuilder();
        private static IContainer _container;

        /// <summary>
        /// 构建IOC容器，需在各种Register后调用。
        /// </summary>
        public static IServiceProvider Build(IServiceCollection services)
        {
            _builder.RegisterModule(new AutofacModuleRegister());
            _builder.Populate(services);
            _container = _builder.Build();
            return new AutofacServiceProvider(_container);
        }

        /// <summary>
        /// Resolve an instance of the default requested type from the container
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <returns></returns>
        public static T Resolve<T>()
        {
            return _container.Resolve<T>();
        }

        public static T Resolve<T>(params Parameter[] parameters)
        {
            return _container.Resolve<T>(parameters);
        }

        public static object Resolve(Type targetType)
        {
            return _container.Resolve(targetType);
        }

        public static object Resolve(Type targetType, params Parameter[] parameters)
        {
            return _container.Resolve(targetType, parameters);
        }
    }

    /// <summary>
    /// Autofac帮助类
    /// </summary>
    public class IocManager
    {
        public static IocManager Instance = new IocManager();

        public ILifetimeScope Container { get; set; }

        public T GetService<T>()
        {
            return Container.Resolve<T>();
        }

        public T GetService<T>(string serviceKey)
        {
            return Container.ResolveKeyed<T>(serviceKey);
        }

        public T GetService<T>(string serviceKey, params Parameter[] parameters)
        {
            return Container.ResolveKeyed<T>(serviceKey, parameters);
        }

        public object GetService(Type serviceType)
        {
            return Container.Resolve(serviceType);
        }

        public object GetService(string serviceKey, Type serviceType)
        {
            return Container.ResolveKeyed(serviceKey, serviceType);
        }

        public bool IsRegistered<T>()
        {
            return Container.IsRegistered<T>();
        }

        public bool IsRegistered<T>(string serviceKey)
        {
            return Container.IsRegisteredWithKey<T>(serviceKey);
        }

        public bool IsRegistered(Type serviceType)
        {
            return Container.IsRegistered(serviceType);
        }

        public bool IsRegisteredWithKey(string serviceKey, Type serviceType)
        {
            return Container.IsRegisteredWithKey(serviceKey, serviceType);
        }
    }
}